package com.kartoshka.painters 
{
	import flash.geom.Matrix;
	import flash.display.Graphics;

	/**
	 * @author Alexander Zats, 2009
	 */
	public class BorderGradientPainter extends NullPainter
	{

		private var _angle : Number;
		private var _colors : Array;
		private var _alphas : Array;
		private var _ratios : Array;
		private var _gradientType : String;
		private var _tx : Number;
		private var _ty : Number;

		private var _thickness : Number;
		protected var _lineType : String;
		private var gradientMatrix : Matrix;

		public function BorderGradientPainter( thickness : Number = 1, colors : Array = null, lineType : String = "inside", angle : Number = Math.PI / 2, gradientType : String = "linear", tx : Number = 0, ty : Number = 0, ratios : Array = null, alphas : Array = null )
		{
			super( );
			this.lineType = lineType;
			this.thickness = thickness; 

			_colors = colors ? colors.concat( ) : [ 0xFFFFFF, 0xCCCCCC ];

			_angle = angle;
			
			_gradientType = gradientType;
			
			var i : int;
			
			_alphas = [];
			if ( ! alphas )
			{
				for ( i = 0; i < _colors.length ; i++ ) _alphas[ _alphas.length ] = 1;
			}
			else
			{
				_alphas = alphas.concat( );
			}
			
			_ratios = [];
			if ( ! ratios )
			{
				for ( i = 0; i < _colors.length ; i++ ) _ratios[ _ratios.length ] = i / ( _colors.length - 1 ) * 0xFF;
			}
			else
			{
				_ratios = ratios.concat( );			}
			
			_tx = tx;
			_ty = ty;
			
			gradientMatrix = new Matrix( );
		}

		override public function draw(graphics : Graphics, width : Number, height : Number) : void
		{
			//TODO there seems to be an error, need to check if cornerRadius more then thickness or less.
			gradientMatrix.identity( );
			gradientMatrix.createGradientBox( width, height, _angle, _tx < 1 ? _tx * width : _tx, _ty < 1 ? _ty * height : _ty );
			
			graphics.beginGradientFill( _gradientType, _colors, _alphas, _ratios, gradientMatrix );
			
			var doubleThickness : Number = _thickness * 2;
			var halfThickness : Number = _thickness / 2;
			if ( cornerRadius )
			{
				switch ( _lineType )
				{
					case "outside":
						graphics.drawRoundRect( - _thickness, - _thickness, width + doubleThickness, height + doubleThickness, cornerRadius + _thickness, cornerRadius + _thickness );
						graphics.drawRoundRect( 0, 0, width, height, cornerRadius, cornerRadius );
						break;
					case "inside":
						graphics.drawRoundRect( 0, 0, width, height, cornerRadius, cornerRadius );
						graphics.drawRoundRect( _thickness, _thickness, width - doubleThickness, height - doubleThickness, cornerRadius - _thickness, cornerRadius - _thickness );
						break;
					default:
						graphics.drawRoundRect( - halfThickness, - halfThickness, width + _thickness, height + _thickness, cornerRadius + halfThickness, cornerRadius + halfThickness );
						graphics.drawRoundRect( halfThickness, halfThickness, width - _thickness, height - _thickness, cornerRadius - halfThickness, cornerRadius - halfThickness );
						break;
				}
			}
			else
			{
				switch ( _lineType )
				{
					case "outside":
						graphics.drawRect( - _thickness, - _thickness, width + doubleThickness, height + doubleThickness );
						graphics.drawRect( 0, 0, width, height );
						break;
					case "inside":
						graphics.drawRect( 0, 0, width, height );
						graphics.drawRect( _thickness, _thickness, width - doubleThickness, height - doubleThickness );
						break;
					default:
						graphics.drawRect( - halfThickness, - halfThickness, width + _thickness, height + _thickness );
						graphics.drawRect( halfThickness, halfThickness, width - _thickness, height - _thickness );
						break;
				}
			}

			graphics.endFill( );
		}

		public function set colors( value : Array ) : void
		{
			if ( value == _colors ) return;
			_colors = value;
		}

		public function get colors() : Array
		{
			return _colors;
		}

		public function set alphas( value : Array ) : void
		{
			if ( value == _alphas ) return;
			_alphas = value;
		}

		public function get alphas() : Array
		{
			return _alphas;
		}

		public function set ratios( value : Array ) : void
		{
			if ( value == _ratios ) return;
			_ratios = value;
		}

		public function get ratios() : Array
		{
			return _ratios;
		}

		public function set angle( value : Number ) : void
		{
			if ( value == _angle ) return;
			_angle = value;
		}

		public function get angle() : Number
		{
			return _angle;
		}

		public function set gradientType( value : String ) : void
		{
			if ( value == _gradientType ) return;
			_gradientType = value;
		}

		public function get gradientType() : String
		{
			return _gradientType;
		}

		/**
		 * The distance, in pixels, to translate to the right along the x axis. This value is offset by half of the width parameter.
		 * @param value Offset, if value less then <code>1</code> then offset will calculated as portion multiplied to width.
		 */
		public function set tx( value : Number ) : void
		{
			if ( value == _tx ) return;
			_tx = value;
		}

		/**
		 * @private
		 */
		public function get tx() : Number
		{
			return _tx;
		}

		/**
		 * The distance, in pixels, to translate down along the y axis. This value is offset by half of the height parameter. 
		 * @private Offset, if value less then <code>1</code> then offset will calculated as portion multiplied to height.
		 */
		public function set ty( value : Number ) : void
		{
			if ( value == _ty ) return;
			_ty = value;
		}

		/**
		 * @private
		 */
		public function get ty() : Number
		{
			return _ty;
		}

		public function set lineType( value : String ) : void
		{
			if ( value == _lineType ) return;
			if ( value == "outside" ) _lineType = "outside";
			else if ( value == "inside" ) _lineType = "inside";
			else _lineType = "center"; 
		}

		public function get lineType() : String
		{
			return _lineType;
		}

		public function set thickness( value : Number ) : void
		{
			if ( value == _thickness ) return;
			_thickness = value;
		}

		public function get thickness() : Number
		{
			return _thickness;
		}
	}
}
